import Types.Remote
import Annex.Common
import qualified Git
-#ifdef WITH_SERVANT
import qualified Annex
import Annex.UUID
import Annex.Url
import Control.Concurrent.Async
import Control.Concurrent
import System.IO.Unsafe
-#endif
import Data.Time.Clock.POSIX
import qualified Data.ByteString.Lazy as L
type ClientAction a
-#ifdef WITH_SERVANT
= ClientEnv
-> ProtocolVersion
-> B64UUID ServerSide
-> [B64UUID Bypass]
-> Maybe Auth
-> Annex (Either ClientError a)
-#else
- = ()
-#endif
p2pHttpClient
:: Remote
-> (String -> Annex a)
-> ClientAction a
-> Annex (Maybe a)
-#ifdef WITH_SERVANT
p2pHttpClientVersions' allowedversion rmt rmtrepo fallback clientaction =
case p2pHttpBaseUrl <$> remoteAnnexP2PHttpUrl (gitconfig rmt) of
Nothing -> error "internal"
putTMVar ccv $ Git.CredentialCache $
M.insert (Git.CredentialBaseURL credentialbaseurl) cred cc
Nothing -> noop
-#else
-p2pHttpClientVersions' _ _ _ fallback () = Just <$> fallback
- "This remote uses an annex+http url, but this version of git-annex is not built with support for that."
-#endif
clientGet
:: Key
-> Maybe FileSize
-- ^ Size of existing file, when resuming.
-> ClientAction Validity
-#ifdef WITH_SERVANT
clientGet k af consumer startsz clientenv (ProtocolVersion ver) su cu bypass auth = liftIO $ do
let offset = fmap (Offset . fromIntegral) startsz
withClientM (cli (B64Key k) cu bypass baf offset auth) clientenv $ \case
gather' (S.Yield v s) = LI.Chunk v <$> unsafeInterleaveIO (gather' s)
baf = associatedFileToB64FilePath af
-#else
-clientGet _ _ _ _ = ()
-#endif
clientCheckPresent :: Key -> ClientAction Bool
-#ifdef WITH_SERVANT
clientCheckPresent key clientenv (ProtocolVersion ver) su cu bypass auth =
liftIO $ withClientM (cli su (B64Key key) cu bypass auth) clientenv $ \case
Left err -> return (Left err)
_ :<|> _ :<|> _ :<|> _ :<|> _ :<|>
v4 :<|> v3 :<|> v2 :<|> v1 :<|> v0 :<|> _ = client p2pHttpAPI
-#else
-clientCheckPresent _ = ()
-#endif
-- Similar to P2P.Protocol.remove.
clientRemoveWithProof
useversion v = v >= ProtocolVersion 3
clientRemove :: Key -> ClientAction RemoveResultPlus
-#ifdef WITH_SERVANT
clientRemove k clientenv (ProtocolVersion ver) su cu bypass auth =
liftIO $ withClientM cli clientenv return
where
_ :<|> _ :<|> _ :<|> _ :<|> _ :<|>
_ :<|> _ :<|> _ :<|> _ :<|> _ :<|>
v4 :<|> v3 :<|> v2 :<|> v1 :<|> v0 :<|> _ = client p2pHttpAPI
-#else
-clientRemove _ = ()
-#endif
clientRemoveBefore
:: Key
-> Timestamp
-> ClientAction RemoveResultPlus
-#ifdef WITH_SERVANT
clientRemoveBefore k ts clientenv (ProtocolVersion ver) su cu bypass auth =
liftIO $ withClientM (cli su (B64Key k) cu bypass ts auth) clientenv return
where
_ :<|> _ :<|> _ :<|> _ :<|> _ :<|>
_ :<|>_ :<|> _ :<|> _ :<|> _ :<|>
v4 :<|> v3 :<|> _ = client p2pHttpAPI
-#else
-clientRemoveBefore _ _ = ()
-#endif
clientGetTimestamp :: ClientAction GetTimestampResult
-#ifdef WITH_SERVANT
clientGetTimestamp clientenv (ProtocolVersion ver) su cu bypass auth =
liftIO $ withClientM (cli su cu bypass auth) clientenv return
where
_ :<|> _ :<|> _ :<|> _ :<|> _ :<|>
_ :<|> _ :<|>
v4 :<|> v3 :<|> _ = client p2pHttpAPI
-#else
-clientGetTimestamp = ()
-#endif
clientPut
:: MeterUpdate
-- ^ Set data-present parameter and do not actually send data
-- (v4+ only)
-> ClientAction PutResultPlus
-#ifdef WITH_SERVANT
clientPut meterupdate k moffset af contentfile contentfilesize validitycheck datapresent clientenv (ProtocolVersion ver) su cu bypass auth
| datapresent = liftIO $ withClientM (cli mempty) clientenv return
| otherwise = do
_ :<|> _ :<|>
_ :<|> _ :<|>
v4 :<|> v3 :<|> v2 :<|> v1 :<|> v0 :<|> _ = client p2pHttpAPI
-#else
-clientPut _ _ _ _ _ _ _ _ = ()
-#endif
clientPutOffset
:: Key
-> ClientAction PutOffsetResultPlus
-#ifdef WITH_SERVANT
clientPutOffset k clientenv (ProtocolVersion ver) su cu bypass auth
| ver == 0 = return (Right (PutOffsetResultPlus (Offset 0)))
| otherwise = liftIO $ withClientM cli clientenv return
_ :<|> _ :<|>
_ :<|> _ :<|> _ :<|> _ :<|> _ :<|>
v4 :<|> v3 :<|> v2 :<|> v1 :<|> _ = client p2pHttpAPI
-#else
-clientPutOffset _ = ()
-#endif
clientLockContent
:: Key
-> ClientAction LockResult
-#ifdef WITH_SERVANT
clientLockContent k clientenv (ProtocolVersion ver) su cu bypass auth =
liftIO $ withClientM (cli (B64Key k) cu bypass auth) clientenv return
where
_ :<|> _ :<|> _ :<|> _ :<|> _ :<|>
_ :<|> _ :<|> _ :<|> _ :<|>
v4 :<|> v3 :<|> v2 :<|> v1 :<|> v0 :<|> _ = client p2pHttpAPI
-#else
-clientLockContent _ = ()
-#endif
clientKeepLocked
:: LockID
-- server. The lock will remain held until the callback returns,
-- and then will be dropped.
-> ClientAction a
-#ifdef WITH_SERVANT
clientKeepLocked lckid remoteuuid unablelock callback clientenv (ProtocolVersion ver) su cu bypass auth = do
readyv <- liftIO newEmptyTMVarIO
keeplocked <- liftIO newEmptyTMVarIO
_ :<|> _ :<|> _ :<|> _ :<|>
_ :<|> _ :<|> _ :<|> _ :<|> _ :<|>
v4 :<|> v3 :<|> v2 :<|> v1 :<|> v0 :<|> _ = client p2pHttpAPI
-#else
-clientKeepLocked _ _ _ _ = ()
-#endif
import qualified P2P.Protocol as P2P
import Utility.MonotonicClock
-#ifdef WITH_SERVANT
import Servant
import Data.Aeson hiding (Key)
import Text.Read (readMaybe)
-#endif
import qualified Data.Text as T
import qualified Data.Text.Encoding as TE
import qualified Data.ByteString as B
data Auth = Auth B.ByteString B.ByteString
deriving (Show, Generic, NFData, Eq, Ord)
-#ifdef WITH_SERVANT
-
instance ToHttpApiData Auth where
toHeader (Auth u p) = "Basic " <> B64.encode (u <> ":" <> p)
#if MIN_VERSION_text(2,0,0)
dePlus (PutOffsetResultAlreadyHavePlus _) = PutOffsetResultAlreadyHave
plus (PutOffsetResult o) = PutOffsetResultPlus o
plus PutOffsetResultAlreadyHave = PutOffsetResultAlreadyHavePlus []
-
-#endif
import Data.List
import Network.URI
-#ifdef WITH_SERVANT
import System.FilePath.Posix as P
import Servant.Client (BaseUrl(..), Scheme(..))
import Text.Read
import Data.Char
import qualified Git
import qualified Git.Url
-#endif
defaultP2PHttpProtocolPort :: Int
defaultP2PHttpProtocolPort = 9417 -- Git protocol is 9418
data P2PHttpUrl = P2PHttpUrl
{ p2pHttpUrlString :: String
-#ifdef WITH_SERVANT
, p2pHttpBaseUrl :: BaseUrl
-#endif
}
deriving (Show)
parseP2PHttpUrl us
| isP2PHttpProtocolUrl us = case parseURI (drop prefixlen us) of
Nothing -> Nothing
-#ifdef WITH_SERVANT
Just u ->
case uriScheme u of
"http:" -> mkbaseurl Http u
"https:" -> mkbaseurl Https u
_ -> Nothing
-#else
- Just _u ->
- Just $ P2PHttpUrl us
-#endif
| otherwise = Nothing
where
prefixlen = length "annex+"
-#ifdef WITH_SERVANT
mkbaseurl s u = do
auth <- uriAuthority u
port <- if null (uriPort auth)
basepath u = case reverse $ P.splitDirectories (uriPath u) of
("git-annex":"/":rest) -> P.joinPath (reverse rest)
rest -> P.joinPath (reverse rest)
-#endif
unavailableP2PHttpUrl :: P2PHttpUrl -> P2PHttpUrl
unavailableP2PHttpUrl p = p
-#ifdef WITH_SERVANT
{ p2pHttpBaseUrl = (p2pHttpBaseUrl p) { baseUrlHost = "!dne!" } }
-#endif
-#ifdef WITH_SERVANT
-- When a p2phttp url is on the same host as a git repo, which also uses
-- http, the same username+password is assumed to be used for both.
isP2PHttpSameHost :: P2PHttpUrl -> Git.Repo -> Bool
Just (map toLower $ baseUrlHost (p2pHttpBaseUrl u))
==
(map toLower <$> (Git.Url.host repo))
-#endif